﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;



namespace MEMDB
{
    public enum error_code
    {
        FAIL = 0,

        SUCCESS = 2,
    };
    public enum ZLib_Error_code
    {
        Z_OK = 0, Z_STREAM_END = 1, Z_NEED_DICT = 2, Z_ERRNO = -1,
        Z_STREAM_ERROR = -2, Z_DATA_ERROR = -3, Z_MEM_ERROR = -4,
        Z_BUF_ERROR = -5, Z_VERSION_ERROR = -6
    }

    public class SQLCommand
    {
        public SQLConnection m_connection;
        public ParameterCollaboration m_Parameters;
        public string m_commandString;
        public string m_strRetMessage;

        [DllImport("zlib.dll", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
        public static extern int uncompress(Byte[] resumedstr, ref int resumedSize, Byte[] compressedstr, int compressedLen);


        public SQLCommand(string sqlCommand, SQLConnection conn)
        {
            m_commandString = sqlCommand;
            m_connection = conn;
            m_Parameters = new ParameterCollaboration();
        }

        public string GetDBInfo()
        {
            if (m_connection == null || m_connection.m_socket == null || m_connection.Connected == false)
                throw new SQLException("无连接");

            if (!GetParameterName(m_commandString, 0).Trim().ToLower().Equals("peer"))
                throw new SQLException("peer语句应使用GetDBInfo函数");

            ReplaceString();

            SendCmd(m_commandString);

            return m_strRetMessage;
        }

        public int ExecuteNonQuery()
        {
            if (m_connection == null || m_connection.m_socket == null || m_connection.Connected == false)
                throw new SQLException("无连接");

            if (GetParameterName(m_commandString, 0).Trim().ToLower().Equals("select"))
                throw new SQLException("select语句应使用ExecuteQuery函数");

            ReplaceString();

            return SendCmd(m_commandString);
        }

        public ResultDataSet ExecuteQuery()
        {
            if (m_connection == null || m_connection.m_socket == null || m_connection.Connected == false)
                throw new SQLException("无连接");

            if (!GetParameterName(m_commandString, 0).Trim().ToLower().Equals("select"))
                throw new SQLException("非select语句应使用ExecuteNonQuery函数");

            ReplaceString();

            return RetrieveDataSet(m_commandString);
        }


        private ResultDataSet RetrieveDataSet(string strCommand)
        {
            const int messageUnitSize = 1000;
            byte[] tempbuf = new byte[8];
            byte[] bufRet = new byte[messageUnitSize];
            byte[] bufResumed;
            byte[] buf = Encoding.Unicode.GetBytes(strCommand);
            try
            {
                m_connection.m_socket.Send(buf);
            }
            catch (System.Exception ex)
            {
                throw new SQLException("连接已关闭。");
            }
            int recvSize = m_connection.m_socket.Receive(bufRet);
            byte[] bytePre;
            int msgType = BitConverter.ToInt32(bufRet, 0);
            int packetLen = BitConverter.ToInt32(bufRet, 4);

            if (msgType != 111111)
            {
                m_strRetMessage = Encoding.Unicode.GetString(bufRet, 8, bufRet.Length - 8);
                return null;
            }

            int originalPacketLen = BitConverter.ToInt32(bufRet, 8);

            if (packetLen > messageUnitSize)
            {
                bytePre = new byte[bufRet.Length];
                bufRet.CopyTo(bytePre, 0);
                bufRet = new byte[packetLen + 10];
                bytePre.CopyTo(bufRet, 0);
            }
            while (recvSize < packetLen)
            {
                recvSize += m_connection.m_socket.Receive(bufRet, recvSize, packetLen - recvSize, 0);
            }

            originalPacketLen += 100;
            bufResumed = new byte[originalPacketLen];

            byte[] tempBuf = new byte[packetLen - 12];
            for (int i = 12; i < packetLen; ++i)
            {
                tempBuf[i - 12] = bufRet[i];
            }

            //送给uncompress的数据有问题
            int i_ret = uncompress(bufResumed, ref originalPacketLen, tempBuf, packetLen - 12);

            if (i_ret != (int)ZLib_Error_code.Z_OK)
                throw new SQLException("解压时出错！");

            ResultDataSet ResultData = new ResultDataSet();

            ResultData.Convert_Data(bufResumed);
            m_strRetMessage = "查询成功，返回" + ResultData.getRowCount() + "条结果。";
            return ResultData;
        }

        public string getRetMsg()
        {
            String strTokens = "\0";
            m_strRetMessage = m_strRetMessage.TrimEnd(strTokens.ToCharArray());
            return m_strRetMessage;
        }

        // 如果返回-1， 说明执行错误
        private int SendCmd(string strCommand)
        {
            const int messageUnitSize = 8192;
            byte[] bufRet = new byte[messageUnitSize];
            byte[] buf = Encoding.Unicode.GetBytes(strCommand);
            try
            {
                m_connection.m_socket.Send(buf);
                m_connection.m_socket.Receive(bufRet);
                int error = BitConverter.ToInt32(bufRet, 0);
                int iAffectedRow = BitConverter.ToInt32(bufRet, 4);

                if ((error_code)error != error_code.SUCCESS)
                {
                    m_strRetMessage = Encoding.Unicode.GetString(bufRet, 8, bufRet.Length - 8);
                    throw new SQLException(m_strRetMessage);
                }

                m_strRetMessage = Encoding.Unicode.GetString(bufRet, 8, bufRet.Length - 8);
                return iAffectedRow;
            }
            catch (SQLException ex)
            {
                throw ex;
            }
            catch(Exception ex2)
            {
                throw new SQLException(ex2.Message);
            }
          }

        private void ReplaceString()
        {
            int i = 0;
            int iParameterIndex = 0;
            int iOldIndex = 0;
            string newCommandString = null;
            string strParamter = null;

            while ((iParameterIndex = m_commandString.IndexOf('@', iOldIndex)) != -1)
            {
                strParamter = GetParameterName(m_commandString, iParameterIndex + 1);
                if (i >= m_Parameters.m_Parameters.Count)
                    throw new SQLException("参数数量不匹配");

                if (!strParamter.Equals(m_Parameters.m_Parameters[i].m_parameterName.Substring(1)))
                    throw new SQLException("参数名不匹配");

                newCommandString += m_commandString.Substring(iOldIndex, iParameterIndex - iOldIndex);
                if (m_Parameters.m_Parameters[i].m_Type == SqlType.NChar)
                    newCommandString += '\'';

                newCommandString += m_Parameters.m_Parameters[i].m_Value.ToString();

                if (m_Parameters.m_Parameters[i].m_Type == SqlType.NChar)
                    newCommandString += '\'';
                i++;
                iOldIndex = iParameterIndex + strParamter.Length + 1;
            }

            if (m_Parameters.m_Parameters.Count > i)
                throw new SQLException("参数数量不匹配");
        }

        public static string GetParameterName(string commandString, int index)
        {
            string str = "";
            for (int i = index; i < commandString.Length && commandString[i] != '\"' && commandString[i] != ' ' && commandString[i] != '\t' && commandString[i] != ',' && commandString[i] != '\n' && commandString[i] != ';'; i++)
            {
                str += commandString[i];
            }
            return str;
        }
    }
}